/ `CFX_Face` 类是 PDFium 项目中用于表示字体面（font face）的核心类。它封装了 FreeType 字体库的功能，提供了对字体数据的访问和操作接口，确保在渲染 PDF 文档中的文本时能够正确处理各种字体特性。以下是 `CFX_Face` 类的详细解析：

### 类定义

```cpp
class CFX_Face final : public Retainable, public Observable {
public:
  using CharMap = void*;

  struct CharCodeAndIndex {
    uint32_t char_code;
    uint32_t glyph_index;
  };

  // Static factory methods for creating CFX_Face instances.
  static RetainPtr<CFX_Face> New(FT_Library library,
    RetainPtr<Retainable> pDesc,
    pdfium::span<const FT_Byte> data,
    FT_Long face_index);

  static RetainPtr<CFX_Face> Open(FT_Library library,
    const FT_Open_Args* args,
    FT_Long face_index);

  // Font properties and metadata.
  bool HasGlyphNames() const;
  bool IsTtOt() const;
  bool IsTricky() const;
  bool IsFixedWidth() const;

#if defined(PDF_ENABLE_XFA)
  bool IsScalable() const;
  void ClearExternalStream();
#endif

  bool IsItalic() const;
  bool IsBold() const;

  ByteString GetFamilyName() const;
  ByteString GetStyleName() const;

  FX_RECT GetBBox() const;
  uint16_t GetUnitsPerEm() const;
  int16_t GetAscender() const;
  int16_t GetDescender() const;
#if BUILDFLAG(IS_ANDROID)
  int16_t GetHeight() const;
#endif

  pdfium::span<uint8_t> GetData() const;

  size_t GetSfntTable(uint32_t table, pdfium::span<uint8_t> buffer);

  std::optional<std::array<uint32_t, 4>> GetOs2UnicodeRange();
  std::optional<std::array<uint32_t, 2>> GetOs2CodePageRange();
  std::optional<std::array<uint8_t, 2>> GetOs2Panose();

  int GetGlyphCount() const;
  FX_RECT GetGlyphBBox() const;
  std::unique_ptr<CFX_GlyphBitmap> RenderGlyph(const CFX_Font* pFont,
    uint32_t glyph_index,
    bool bFontStyle,
    const CFX_Matrix& matrix,
    int dest_width,
    int anti_alias);
  std::unique_ptr<CFX_Path> LoadGlyphPath(uint32_t glyph_index,
    int dest_width,
    bool is_vertical,
    const CFX_SubstFont* subst_font);
  int GetGlyphWidth(uint32_t glyph_index,
    int dest_width,
    int weight,
    const CFX_SubstFont* subst_font);
  ByteString GetGlyphName(uint32_t glyph_index);

  int GetCharIndex(uint32_t code);
  int GetNameIndex(const char* name);

  FX_RECT GetCharBBox(uint32_t code, int glyph_index);

  std::vector<CharCodeAndIndex> GetCharCodesAndIndices(char32_t max_char);

  CharMap GetCurrentCharMap() const;
  std::optional<fxge::FontEncoding> GetCurrentCharMapEncoding() const;
  int GetCharMapPlatformIdByIndex(size_t index) const;
  int GetCharMapEncodingIdByIndex(size_t index) const;
  fxge::FontEncoding GetCharMapEncodingByIndex(size_t index) const;
  size_t GetCharMapCount() const;
  void SetCharMap(CharMap map);
  void SetCharMapByIndex(size_t index);
  bool SelectCharMap(fxge::FontEncoding encoding);

  bool SetPixelSize(uint32_t width, uint32_t height);

#if BUILDFLAG(IS_WIN)
  bool CanEmbed();
#endif

  FXFT_FaceRec* GetRec() { return m_pRec.get(); }
  const FXFT_FaceRec* GetRec() const { return m_pRec.get(); }

private:
  CFX_Face(FXFT_FaceRec* pRec, RetainPtr<Retainable> pDesc);
  ~CFX_Face() override;

  void AdjustVariationParams(int glyph_index, int dest_width, int weight);

  ScopedFXFTFaceRec const m_pRec;
  RetainPtr<Retainable> const m_pDesc;
};
```

### 主要功能

#### 1. * *字体创建和管理 * *

-**静态工厂方法 * *：
- `New` 和 `Open` 是两个静态工厂方法，用于创建 `CFX_Face` 实例。`New` 方法通过提供字体数据和索引创建字体面，而 `Open` 方法则使用 FreeType 的 `FT_Open_Args` 结构来打开字体文件或流。

#### 2. * *字体属性查询 * *

-**字体特性 * *：
- `HasGlyphNames`：检查字体是否包含字形名称。
- `IsTtOt`：判断字体是否为 TrueType 或 OpenType 字体。
- `IsTricky`：判断字体是否需要特殊处理（例如某些复杂的字体格式）。
- `IsFixedWidth`：判断字体是否为等宽字体。
- `IsItalic`：判断字体是否为斜体。
- `IsBold`：判断字体是否为粗体。
- `IsScalable`（仅在 XFA 模式下可用）：判断字体是否可缩放。

- **字体元数据 * *：
- `GetFamilyName`：获取字体家族名称。
- `GetStyleName`：获取字体样式名称。
- `GetBBox`：获取字体的整体边界框。
- `GetUnitsPerEm`：获取字体的单位每 EM 值。
- `GetAscender`：获取字体的上沿值。
- `GetDescender`：获取字体的下沿值。
- `GetHeight`（仅在 Android 平台上可用）：获取字体的高度。

#### 3. * *字体表数据访问 * *

-**SFNT 表 * *：
- `GetSfntTable`：获取指定的 SFNT 表数据（如 `cmap`、`glyf` 等），并将其写入提供的缓冲区中。

- **OS / 2 表 * *：
- `GetOs2UnicodeRange`：获取 OS / 2 表中的 Unicode 范围信息。
- `GetOs2CodePageRange`：获取 OS / 2 表中的代码页范围信息。
- `GetOs2Panose`：获取 OS / 2 表中的 Panose 字体分类信息。

#### 4. * *字形操作 * *

-**字形数量 * *：
- `GetGlyphCount`：获取字体中的字形总数。

- **字形边界框 * *：
- `GetGlyphBBox`：获取所有字形的总体边界框。

- **字形渲染 * *：
- `RenderGlyph`：渲染指定的字形为位图，并返回一个 `CFX_GlyphBitmap` 对象。
- `LoadGlyphPath`：加载指定字形的路径数据，并返回一个 `CFX_Path` 对象。

- **字形宽度 * *：
- `GetGlyphWidth`：获取指定字形的宽度。

- **字形名称 * *：
- `GetGlyphName`：获取指定字形的名称（如果字体支持字形名称）。

#### 5. * *字符映射 * *

-**字符索引 * *：
- `GetCharIndex`：根据字符代码获取对应的字形索引。
- `GetNameIndex`：根据字符名称获取对应的字形索引。

- **字符边界框 * *：
- `GetCharBBox`：获取指定字符的边界框。

- **字符代码和字形索引映射 * *：
- `GetCharCodesAndIndices`：获取从字符代码到字形索引的映射关系。

#### 6. * *字符映射管理 * *

-**当前字符映射 * *：
- `GetCurrentCharMap`：获取当前使用的字符映射。
- `GetCurrentCharMapEncoding`：获取当前字符映射的编码类型。
- `GetCharMapPlatformIdByIndex`：根据索引获取字符映射的平台 ID。
- `GetCharMapEncodingIdByIndex`：根据索引获取字符映射的编码 ID。
- `GetCharMapEncodingByIndex`：根据索引获取字符映射的编码类型。
- `GetCharMapCount`：获取字符映射的数量。

- **设置字符映射 * *：
- `SetCharMap`：设置当前使用的字符映射。
- `SetCharMapByIndex`：根据索引设置字符映射。
- `SelectCharMap`：根据编码类型选择字符映射。

#### 7. * *像素大小设置 * *

-**设置像素大小 * *：
- `SetPixelSize`：设置字体的像素大小（宽度和高度）。

#### 8. * *嵌入支持 * *

-**嵌入支持 * *（仅在 Windows 平台上可用）：
- `CanEmbed`：检查字体是否可以嵌入到文档中。

#### 9. * *FreeType 内部结构访问 * *

-**获取 FreeType 面记录 * *：
- `GetRec`：获取底层的 FreeType 面记录（`FXFT_FaceRec`），用于直接访问 FreeType 提供的功能。

### 私有成员

- **构造函数和析构函数 * *：
- `CFX_Face` 构造函数接受一个 `FXFT_FaceRec` 指针和一个描述符对象 `pDesc`，并在内部初始化字体面。
- `~CFX_Face` 析构函数负责释放资源。

- **调整变体参数 * *：
- `AdjustVariationParams`：调整字形的变体参数（如宽度和权重），以适应不同的渲染需求。

- **成员变量 * *：
- `m_pRec`：指向 FreeType 面记录的智能指针，用于管理字体面的生命周期。
- `m_pDesc`：指向描述符对象的智能指针，用于存储与字体相关的额外信息。

### 实际应用

`CFX_Face` 类在 PDFium 中扮演着至关重要的角色，特别是在以下场景中：

1. * *字体加载和渲染 * *：
- 当 PDF 文档中引用的字体需要加载时，`CFX_Face` 提供了必要的接口来创建和管理字体面。通过 `RenderGlyph` 和 `LoadGlyphPath` 等方法，PDFium 可以将字体中的字形渲染为位图或路径，从而实现文本的显示。

2. * *字体属性查询 * *：
- 在处理 PDF 文档时，可能需要查询字体的各种属性（如是否为等宽字体、是否为斜体等）。`CFX_Face` 提供了丰富的接口来获取这些信息，确保文本渲染的准确性。

3. * *字符映射管理 * *：
- 不同的字体可能使用不同的字符映射表（如 `cmap`），`CFX_Face` 提供了灵活的字符映射管理功能，确保在不同编码环境下正确映射字符代码到字形索引。

4. * *跨平台支持 * *：
- `CFX_Face` 封装了 FreeType 字体库的功能，使得 PDFium 可以在不同平台上一致地处理字体。无论是 Windows、Linux 还是 Android，`CFX_Face` 都能提供可靠的字体管理和渲染功能。

5. * *字体嵌入 * *：
- 在某些情况下，PDF 文档可能需要嵌入字体以确保文本在不同设备上的显示一致性。`CFX_Face` 提供了嵌入支持功能，确保字体可以正确嵌入到文档中。

### 总结

`CFX_Face` 类是 PDFium 中处理字体的核心组件，它不仅提供了对 FreeType 字体库的封装，还实现了丰富的字体管理和渲染功能。通过 `CFX_Face`，PDFium 可以在不同平台上高效地加载、查询和渲染字体，确保 PDF 文档中的文本能够正确显示。 / Copyright 2019 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CORE_FXGE_CFX_FACE_H_
#define CORE_FXGE_CFX_FACE_H_

#include <stdint.h>

#include <array>
#include <memory>
#include <optional>
#include <vector>

#include "build/build_config.h"
#include "core/fxcrt/bytestring.h"
#include "core/fxcrt/fx_coordinates.h"
#include "core/fxcrt/observed_ptr.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxcrt/span.h"
#include "core/fxge/freetype/fx_freetype.h"

namespace fxge {
enum class FontEncoding : uint32_t;
}

class CFX_Font;
class CFX_GlyphBitmap;
class CFX_Path;
class CFX_SubstFont;

class CFX_Face final : public Retainable, public Observable {
 public:
  using CharMap = void*;

  struct CharCodeAndIndex {
    uint32_t char_code;
    uint32_t glyph_index;
  };

  static RetainPtr<CFX_Face> New(FT_Library library,
                                 RetainPtr<Retainable> pDesc,
                                 pdfium::span<const FT_Byte> data,
                                 FT_Long face_index);

  static RetainPtr<CFX_Face> Open(FT_Library library,
                                  const FT_Open_Args* args,
                                  FT_Long face_index);

  bool HasGlyphNames() const;
  bool IsTtOt() const;
  bool IsTricky() const;
  bool IsFixedWidth() const;

#if defined(PDF_ENABLE_XFA)
  bool IsScalable() const;
  void ClearExternalStream();
#endif

  bool IsItalic() const;
  bool IsBold() const;

  ByteString GetFamilyName() const;
  ByteString GetStyleName() const;

  FX_RECT GetBBox() const;
  uint16_t GetUnitsPerEm() const;
  int16_t GetAscender() const;
  int16_t GetDescender() const;
#if BUILDFLAG(IS_ANDROID)
  int16_t GetHeight() const;
#endif

  pdfium::span<uint8_t> GetData() const;

  // Returns the size of the data, or 0 on failure. Only write into `buffer` if
  // it is large enough to hold the data.
  size_t GetSfntTable(uint32_t table, pdfium::span<uint8_t> buffer);

  std::optional<std::array<uint32_t, 4>> GetOs2UnicodeRange();
  std::optional<std::array<uint32_t, 2>> GetOs2CodePageRange();
  std::optional<std::array<uint8_t, 2>> GetOs2Panose();

  int GetGlyphCount() const;
  // TODO(crbug.com/pdfium/2037): Can this method be private?
  FX_RECT GetGlyphBBox() const;
  std::unique_ptr<CFX_GlyphBitmap> RenderGlyph(const CFX_Font* pFont,
                                               uint32_t glyph_index,
                                               bool bFontStyle,
                                               const CFX_Matrix& matrix,
                                               int dest_width,
                                               int anti_alias);
  std::unique_ptr<CFX_Path> LoadGlyphPath(uint32_t glyph_index,
                                          int dest_width,
                                          bool is_vertical,
                                          const CFX_SubstFont* subst_font);
  int GetGlyphWidth(uint32_t glyph_index,
                    int dest_width,
                    int weight,
                    const CFX_SubstFont* subst_font);
  ByteString GetGlyphName(uint32_t glyph_index);

  int GetCharIndex(uint32_t code);
  int GetNameIndex(const char* name);

  FX_RECT GetCharBBox(uint32_t code, int glyph_index);

  std::vector<CharCodeAndIndex> GetCharCodesAndIndices(char32_t max_char);

  CharMap GetCurrentCharMap() const;
  std::optional<fxge::FontEncoding> GetCurrentCharMapEncoding() const;
  int GetCharMapPlatformIdByIndex(size_t index) const;
  int GetCharMapEncodingIdByIndex(size_t index) const;
  fxge::FontEncoding GetCharMapEncodingByIndex(size_t index) const;
  size_t GetCharMapCount() const;
  void SetCharMap(CharMap map);
  void SetCharMapByIndex(size_t index);
  bool SelectCharMap(fxge::FontEncoding encoding);

  bool SetPixelSize(uint32_t width, uint32_t height);

#if BUILDFLAG(IS_WIN)
  bool CanEmbed();
#endif

  FXFT_FaceRec* GetRec() { return m_pRec.get(); }
  const FXFT_FaceRec* GetRec() const { return m_pRec.get(); }

 private:
  CFX_Face(FXFT_FaceRec* pRec, RetainPtr<Retainable> pDesc);
  ~CFX_Face() override;

  void AdjustVariationParams(int glyph_index, int dest_width, int weight);

  ScopedFXFTFaceRec const m_pRec;
  RetainPtr<Retainable> const m_pDesc;
};

#endif  // CORE_FXGE_CFX_FACE_H_
